local fileUtils = cc.FileUtils:getInstance()
local dbFactory =  db.CCFactory:getInstance()
local programCache = cc.GLProgramCache:getInstance()
local Director = cc.Director:getInstance()

local Toast = require("app.widget.Toast")

-- 给底层界面设置自适应缩放
function display.setAutoScale(node)
    if cc.isDead(node) then
        return
    end
    local scale = math.min(display.width/display.ui_width, display.height/display.ui_height)
    if scale < 1 then
        node:setScale(scale)
    end
end

function display.newModalDialogWithoutColor()
    local layer = ccui.Layout:create()
    layer:setContentSize(display.size)
    layer:setTouchEnabled(true)
    layer:setSwallowTouches(true)
    return layer
end

function display.newTouchLayer()
    local layer = ccui.Layout:create()
    layer:setContentSize(display.size)
    layer:setTouchEnabled(true)
    layer:setSwallowTouches(true)
    return layer
end

function display.newModalDialog()
    local ModalDialog = require("app.widget.ModalDialog")
    return ModalDialog.new()
end

function display.newBlurSprite(node)
    if cc.isDead(node) then
        return
    end
    local texture = display.newTextureByNode(node)
    local srpite = display.newFilteredSprite(texture,{"GAUSSIAN_HBLUR","GAUSSIAN_VBLUR"},{{1.75}, {1.75}})
    srpite:setScaleY(-1)
    return srpite
end

function display.newBlurDialog()
    local BlurDialog = require("app.widget.BlurDialog")
    return BlurDialog.new()
end

function display.setBlurNode(node)
    local BlurDialog = require("app.widget.BlurDialog")
    BlurDialog.blurNode = node
end

function display.setBeforeBlurCallback(func)
  local BlurDialog = require("app.widget.BlurDialog")
  BlurDialog.beforeBlurCallback = func
end

function display.setAfterBlurCallback(func)
  local BlurDialog = require("app.widget.BlurDialog")
  BlurDialog.afterBlurCallback = func
end

function display.setFinishBlurCallback(func)
  local BlurDialog = require("app.widget.BlurDialog")
  BlurDialog.finishBlurCallback = func
end

function display.newActivityIndicator()
    local viewClass = require("app.widget.ActivityIndicator")
    return viewClass.new()
end

-- 消耗确认Dialog
function display.newCostConfirmDialog( params )
    local CostConfirmDialog = require("app.widget.CostConfirmDialog")
    local CostConfirmDialog = CostConfirmDialog.new( params )
    return CostConfirmDialog
end

function display.newConfirmPayDialog(textContent1,onConfirm,onCancel,textContent2,payType,payAmount,buyAmount)
    local ConfirmPayDialog = require("app.widget.ConfirmPayDialog")
    local confirmPayDialog = ConfirmPayDialog.new(textContent1,onConfirm,onCancel,textContent2,payType,payAmount,buyAmount)
    return confirmPayDialog
end

function display.newConfirmDialog(hint,okFunc,cancelFunc)
    local confirmDialog = app.mvc.DialogBase.new(hint, okFunc, cancelFunc or function() end)
    return confirmDialog
end

function display.newMessageBox(hint,okFunc)
    local messageBox = app.mvc.DialogBase.new(hint, okFunc)
    return messageBox
end

function display.setToastParent(node)
    Toast.setParentNode(node)
end

-- 可以暂时的停止Toast
function display.setToastEnable(b)
  Toast.setEnable(b)
end

function display.pushToast(text, tag)
    Toast.push(text, tag)
end

-- while DEBUG > 0 do it
function display.pushToastDebug(text, tag)
    if DEBUG > 0 then
      Toast.push(text, tag)
    end
end

function display.clearToastByTag(tag)
    Toast.clearByTag(tag)
end

function display.clearToasts()
    Toast.clearAll()
end

function display.setToastVisible(visible)
    Toast.setToastVisible(visible)
end

--[[
@params
  -startFrame :
  -endFrame :
  -loop : boolean
  -autoRemove : auto remove when completed
  -cb : callback function
]]
function display.playCSBAni(file,params)
    local autoRemove = true
    local cb = nil
    local startFrame = 0
    local endFrame = nil
    local loop = false

    if params then
        if params.autoRemove~=nil then
          autoRemove = params.autoRemove
        end
        cb = params.cb
        startFrame = params.startFrame or 0
        endFrame = params.endFrame
        loop = params.loop or false
    end

    local node = cc.CSLoader:createNode(file,false,true)
    if not node then return nil end
    local timeline = cc.CSLoader:createTimeline(file)
    if timeline then
        node:runAction(timeline)
        if endFrame then
          timeline:gotoFrameAndPlay(startFrame,endFrame,loop)
        else
          timeline:gotoFrameAndPlay(startFrame,loop)
        end
        timeline:setLastFrameCallFunc(function()
            if cb then
                cb(node)
            end

            if autoRemove then
                node:removeFromParent()
            end
        end)
    else
        if cb then
            cb()
        end
    end
    return node
end

function display.playDBAni(armature,aniName,cb)
    local DBAniEventType = require("dragonbones.AnimationEventType")
    armature:registerMovementEventHandler(function(type,movementId,finished)
        if DBAniEventType.COMPLETE == type then
            if cb then
                cb()
            end
        elseif DBAniEventType.LOOP_COMPLETE == type then
        end
    end)
    if aniName then
        armature:getAnimation():play(aniName)
    else
        armature:getAnimation():play()
    end
end

local USE_DBB
local DBB_SUFFIX=".bin"
local XML_SUFFIX=".xml"

function display.getArmaturePath(params)
    local path = params.path
    local skeFile = params.skeleton
    local texFile = params.texture

    local skeletonKey
    local textureKey

    local skeletonPath
    local texturePath

    if path then
        skeletonPath = path.."/skeleton"
        texturePath = path.."/texture"
    else
        skeletonPath = skeFile
        texturePath = texFile
    end

    if type(USE_DBB)=="nil" then
      local dbbexist = fileUtils:isFileExist(skeletonPath..DBB_SUFFIX)
      local xmlexist = fileUtils:isFileExist(skeletonPath..XML_SUFFIX)
      if dbbexist or xmlexist then
        USE_DBB = dbbexist
      end
    end

    if not USE_DBB then
        skeletonPath = skeletonPath..XML_SUFFIX
        texturePath = texturePath..XML_SUFFIX
    else
        skeletonPath = skeletonPath..DBB_SUFFIX
        texturePath = texturePath..DBB_SUFFIX
    end

    skeletonKey = fileUtils:fullPathForFilename(skeletonPath)
    textureKey = fileUtils:fullPathForFilename(texturePath)
    return skeletonKey, textureKey, skeletonPath, texturePath
end


--[[

一个提供完整的xml配置文件路径的同步载入：
{
    skeleton="dragon/skeleton.xml",
    texture="dragon/texture.xml",
    armatureName="Dragon",
}

在 path 指定的目录中自动查找 skeleton.xml 和 texture.xml：
{
    path="dragon",
    armatureName="Dragon",
}
--]]
function display.newArmature(params)
    local path = params.path
    local skeFile = params.skeleton
    local texFile = params.texture
    local armName = params.armatureName
    local skinName = params.skinName or ""
    local texAsync = type(params.async)=="nil" and true or params.async

    -- cc.Texture2D:setDefaultAlphaPixelFormat(cc.TEXTURE2_D_PIXEL_FORMAT_RGB_A4444)

    local skeletonKey
    local textureKey

    local skeletonPath
    local texturePath

    skeletonKey, textureKey, skeletonPath, texturePath = display.getArmaturePath(params)

    -- print("armName", armName)
    -- print("skeletonKey", skeletonKey)
    -- print("textureKey", textureKey)
    -- print("skeletonPath", skeletonPath)
    -- print("texturePath", texturePath)

    if not dbFactory:loadDragonBonesData(skeletonPath,skeletonKey) then
      release_print("====>:loadDragonBonesData fail",skeletonPath)
    end

    if not dbFactory:loadTextureAtlasData(texturePath,textureKey,0,texAsync) then
      release_print("====>:loadTextureAtlasData fail",texturePath)
    end


    local armature = dbFactory:buildArmatureDisplay(armName,skeletonKey,textureKey)

    if not armature then
        if path then
          release_print("====>display.newArmature fail path:",path,"armatureName",armName)
        else
          release_print("====>display.newArmature fail skeFile:",skeFile,"armatureName",armName)
        end
    end
    -- cc.Texture2D:setDefaultAlphaPixelFormat(cc.TEXTURE2_D_PIXEL_FORMAT_RGB_A8888)
    return armature, skeletonKey, textureKey
end

function display.purgeUnUsedArmatureCachedData()
    dbFactory:disposeUnused()
end

function display.newAnimationNode(csbFile)
    local node = cc.CSLoader:createNode(csbFile)
    local timeline = cc.CSLoader:createTimeline(csbFile)
    node:runAction(timeline)
    timeline:gotoFrameAndPlay(0,false)

    local duration = timeline:getDuration()/60+0.1
    node:runAction(cc.Sequence:create(
        cc.DelayTime:create(duration),cc.RemoveSelf:create()
    ))
    return node
end

function display.setWidgetOpacity(widget, opacity)
    if not cc.isDead(widget) then
        widget:setOpacity(opacity)
        local children = widget:getChildren()
        local count = widget:getChildrenCount()
        for i=1,count do
            display.setWidgetOpacity(children[i], opacity)
        end
    end
end

function display.setWidgetColor(widget, color)
    if not cc.isDead(widget) then
        widget:setColor(color)
        local children = widget:getChildren()
        local count = widget:getChildrenCount()
        for i=1,count do
            display.setWidgetColor(children[i], color)
        end
    end
end

function display.ScrollViewFill(scrollview, nodes, params)
    if cc.isDead(scrollview) then
        return
    end
  --参数的继承用法,把param2的参数增加覆盖到param1中。
  local extend = function(param1,param2)
    if not param2 then
      return param1
    end
    for k , v in pairs(param2) do
      param1[k] = param2[k]
    end
    return param1
  end

  local params = extend({
    --自动间距
    autoGap = true,
    --宽间距
    widthGap = 0,
    --高间距
    heightGap = 0,
    --自动行列
    autoTable = true,
    --行数目
    rowCount = 3,
    --列数目
    cellCount = 3,
    --填充项大小
    itemSize = cc.size(50 , 50),
    --容器大小根据item多少决定
    autoSize = false,

    upToDown = true,

    -- reverse = false,
    rightToLeft = false,

     --zorder 降序
    zorderDesc = false,

  },params)

  if #nodes == 0 then
    return nil
  end

  --基本坐标工具方法
  local SIZE = function(node) return node:getContentSize() end
  local W = function(node) return node:getContentSize2() end
  local H = function(node)
      local _, height = node:getContentSize2()
      return height
  end
  local S_SIZE = function(node , w , h) return node:setContentSize(cc.size(w , h)) end
  local S_XY = function(node , x , y) node:setPosition(x,y) end
  local AX = function(node) return node:getAnchorPoint().x end
  local AY = function(node) return node:getAnchorPoint().y end

  --创建一个容器node
  -- local innerContainer = display.newNode()
  -- --初始容器大小为视图大小
  -- S_SIZE(innerContainer , self:getViewRect().width , self:getViewRect().height)
  -- self:addScrollNode(innerContainer)
  -- S_XY(innerContainer , self.viewRect_.x , self.viewRect_.y)

  local viewRect_ = scrollview:getInnerContainerSize()

  local innerContainer = scrollview:getInnerContainer()
  local parentNode = innerContainer
  if params.parent then
    parentNode = params.parent
  end
  
  local nodeCount = #nodes
  --如果是纵向布局
  if scrollview:getDirection() == cc.SCROLLVIEW_DIRECTION_VERTICAL then

    --自动布局
    if params.autoTable then
      params.cellCount = math.floor(viewRect_.width / params.itemSize.width)
    end

    --自动间隔
    if params.autoGap then
      params.widthGap = (viewRect_.width - (params.cellCount * params.itemSize.width)) / (params.cellCount + 1)
      params.heightGap = params.widthGap
    end

    --填充量
    params.rowCount = math.ceil(#nodes / params.cellCount)
    --避免动态尺寸少于设计尺寸
    local v_h = (params.itemSize.height + params.heightGap) * params.rowCount + params.heightGap

    if params.autoSize then
    else
      if v_h < viewRect_.height then v_h = viewRect_.height end
    end

    if params.autoSize then
      -- S_SIZE(innerContainer , viewRect_.width , v_h)
      scrollview:setInnerContainerSize(cc.size(viewRect_.width , v_h))
    end


    for i = 1 , #nodes do

      local n = nodes[i]
      local x = 0.0
      local y = 0.0

      --不管描点如何，总是有标准居中方式设置坐标。
      local index = i
      if params.rightToLeft then
        x = W(innerContainer) - (params.widthGap + (math.floor((i - 1) % params.cellCount) + 1) * (params.widthGap + params.itemSize.width))
      else
        x = params.widthGap + math.floor((i - 1) % params.cellCount) * (params.widthGap + params.itemSize.width)
      end

      if params.upToDown then
        y = H(innerContainer) - (math.floor((i - 1) / params.cellCount) + 1) * (params.heightGap + params.itemSize.height)
      else
        y = (math.floor((i - 1) / params.cellCount)) * (params.heightGap + params.itemSize.height)
      end
      x = x + W(n) * AX(n)
      y = y + H(n) * AY(n)

      S_XY(n , x ,y)
      if params.zorderDesc then
        n:addTo(parentNode, nodeCount + 1 - i)
      else
        n:addTo(parentNode)
      end

    end
    --如果是横向布局
    --  elseif(self.direction==cc.ui.UIScrollView.DIRECTION_HORIZONTAL) then
  else
    if params.autoTable then
      params.rowCount = math.floor(viewRect_.height / params.itemSize.height)
    end

    if params.autoGap then
      params.heightGap = (viewRect_.height - (params.rowCount * params.itemSize.height)) / (params.rowCount + 1)
      params.widthGap = params.heightGap
    end

    params.cellCount = math.ceil(#nodes / params.rowCount)
    --避免动态尺寸少于设计尺寸。
    local v_w = (params.itemSize.width + params.widthGap) * params.cellCount + params.widthGap
    if params.autoSize then
    else
      if v_w < viewRect_.width then v_h = viewRect_.width end
    end

    if params.autoSize then
      -- S_SIZE(innerContainer , v_w ,viewRect_.height)
      scrollview:setInnerContainerSize(cc.size(v_w ,viewRect_.height))
    end

    for i = 1, #nodes do

      local n = nodes[i]
      local x = 0.0
      local y = 0.0

      --不管描点如何，总是有标准居中方式设置坐标。
      if params.rightToLeft then
        x = W(innerContainer) - (params.widthGap +  (math.floor((i - 1) / params.rowCount) + 1 ) * (params.widthGap + params.itemSize.width))
      else
        x = params.widthGap +  math.floor((i - 1) / params.rowCount ) * (params.widthGap + params.itemSize.width)
      end

      if params.upToDown then
        y = H(innerContainer) - (math.floor((i - 1) % params.rowCount ) +1 ) * (params.heightGap + params.itemSize.height)
      else
        y = (math.floor((i - 1) % params.rowCount )) * (params.heightGap + params.itemSize.height)
      end
      x = x + W(n) * AX(n)
      y = y + H(n) * AY(n)

      S_XY(n , x , y)
      if params.zorderDesc then
        n:addTo(parentNode, nodeCount + 1 - i)
      else
        n:addTo(parentNode)
      end

    end

  end

end

function display.newTextureByNode(node)
  local renderTexture = cc.RenderTexture:create(display.width,display.height)
  --renderTexture:setPosition(cc.p(display.cx,display.cy))
  renderTexture:begin()
  if not cc.isDead(node) then
      node:visit()
  end
  renderTexture:endToLua()
  return renderTexture:getSprite():getTexture()
end

function display.newTextureByNodes(nodes)
  local renderTexture = cc.RenderTexture:create(display.width,display.height)
  --renderTexture:setPosition(cc.p(display.cx,display.cy))
  renderTexture:begin()
  for k,node in pairs(nodes) do
      if not cc.isDead(node) then
          node:visit()
      end
  end
  renderTexture:endToLua()
  return renderTexture:getSprite():getTexture()
end

-- 渲染获得texture
local RenderNodeQueue = {}
-- 渲染保存文件
local RenderFileQueue = {}
local RenderFileCBDict = {}

-- 一次只渲染一个
function display.updateRenderQueue()
  if #RenderNodeQueue > 0 then
    local task = table.remove(RenderNodeQueue, 1)
    local node,width,height,cb = unpack(task)
    -- print("node,width,height,cb,alive", node,width,height,cb, cc.isAlive(node))
    if cc.isAlive(node) then
      local renderTexture = cc.RenderTexture:create(width,height,cc.TEXTURE2D_PIXEL_FORMAT_RGBA8888,gl.DEPTH24_STENCIL8_OES)
      renderTexture:begin()
      node:setVisible(true)
      node:visit()
      renderTexture:endToLua()

      node:setVisible(false)
      -- renderTexture渲染的node不能在当前帧删除，需要延迟删除
      node:performWithDelay(function() 
        node:removeFromParent(true)
      end, 1)

      local texture = renderTexture:getSprite():getTexture()
      texture:setAntiAliasTexParameters() -- 开启抗锯齿，会有更多内存消耗
      executeFunc(cb, texture)
      return
    end
  end

  if #RenderFileQueue>0 then
    local task = RenderFileQueue[1]
    local node,width,height,fileName,format,isRGBA = unpack(task)
    local cbs = RenderFileCBDict[fileName] or {}
    local renderTexture = cc.RenderTexture:create(width,height,cc.TEXTURE2D_PIXEL_FORMAT_RGBA8888,gl.DEPTH24_STENCIL8_OES)
    renderTexture:retain()
    renderTexture:begin()
    node:setVisible(true)
    node:visit()
    renderTexture:endToLua()
    renderTexture:saveToFile(fileName,format,isRGBA,function(sender,name)
        for _,cb in ipairs(cbs) do
            if cb then
              cb(name)
            end
        end
        renderTexture:release()
        node:removeFromParent(true)
    end)
    node:setVisible(false)
    table.remove(RenderFileQueue,1)
    RenderFileCBDict[fileName] = nil
  end

end

function display.isRenderNodeInQueue(fileName)
    return RenderFileCBDict[fileName] ~= nil
end

function display.addRenderFileCB(fileName, cb)
    local cbs = RenderFileCBDict[fileName]
    if cbs then
        cbs[#cbs + 1] = cb
    end
end

function display.renderNodeToJpg(node,width,height,fileName,cb)
  if cc.isDead(node) then return end
  RenderFileCBDict[fileName] = {cb}
  table.insert(RenderFileQueue,{node,width,height,fileName,0,false})
  Director:getRunningScene():addChild(node)
  node:setVisible(false)
end

function display.renderNodeToPng(node,width,height,fileName,cb)
  if cc.isDead(node) then return end
  RenderFileCBDict[fileName] = {cb}
  table.insert(RenderFileQueue,{node,width,height,fileName,1,true})
  Director:getRunningScene():addChild(node)
  node:setVisible(false)
end

function display.renderNodeToGetTexture(node, width, height, cb)
    if cc.isDead(node) then return end
    table.insert(RenderNodeQueue, {node, width, height, cb})
    Director:getRunningScene():addChild(node)
    node:setVisible(false)
end

-- textField 提供替换后ExidBox各种参数
-- inputMode inputMode
-- hasMax    设定长度限制
-- notRemove 替换完成是否移除掉textField
function display.replaceTextFieldWithEditBox(textField, inputMode, hasMax, notRemove)
  if not textField then
      print("display.replaceTextFieldWithEditBox textField = nil")
      return
  end
  inputMode = inputMode or cc.EDITBOX_INPUT_MODE_SINGLELINE
  hasMax = hasMax or false
  notRemove = notRemove or false

  local contentSize = textField:getContentSize()
  local parent = textField:getParent()
  local posX,posY = textField:getPosition()
  local scale = textField:getScale()
  local anchorPoint = textField:getAnchorPoint()
  local placeHolderStr = textField:getPlaceHolder()
  local fontName = textField:getFontName()
  local fontSize = textField:getFontSize()
  local isMaxLengthEnabled = textField:isMaxLengthEnabled()
  local maxLength = textField:getMaxLength()
  local fontColor = textField:getTextColor()
  -- local placeholderColor = textField:getPlaceHolderColor()

  local editBox = ccui.EditBox:create(contentSize, "")

  -- 海外平台使用默认字体（各种语言字符）
  if app:isInnerEma() or app:isInnerPwrd() then
    fontName = Res.defaultFont
  end

  parent:addChild(editBox)
  editBox:setAnchorPoint(anchorPoint)
  editBox:setScale(scale)
  editBox:setPosition(cc.p(posX,posY))

  editBox:setPlaceholderFont(fontName, fontSize)
  -- editBox:setPlaceholderFontColor(placeholderColor)
  editBox:setPlaceHolder(placeHolderStr)

  editBox:setFont(fontName, fontSize)
  editBox:setFontColor(fontColor)

  editBox:setVisible(textField:isVisible())
  if isMaxLengthEnabled and hasMax then
      editBox:setMaxLength(maxLength)
  end

  editBox:setInputMode(inputMode)
  editBox:setReturnType(cc.KEYBOARD_RETURNTYPE_DONE)
  if not notRemove then
    textField:removeFromParent()
  end
  return editBox
end

function display.setColor(node,c)
    if cc.isDead(node) then
      return
    end
    node:setColorDeep(c)
end


function display.multiplyColor(node,v)
    if cc.isDead(node) then
      return
    end
    if node.setColor then
        local c = node:getColor()
        c.r = c.r * v
        c.g = c.g * v
        c.b = c.b * v
        node:setColor(c)
    end
    if not node:isCascadeColorEnabled() then
        local children = node:getChildren()
        for i,child in ipairs(children) do
            display.multiplyColor(child,v)
        end
    end
end

function display.setCascadeColorEnabled(node,b)
    if cc.isDead(node) then
        return
    end
    node:setCascadeColorEnabledDeep(b)
end

function display.setCascadeOpacityEnabled(node,b)
    if cc.isDead(node) then
        return
    end
    node:setCascadeOpacityEnabledDeep(b)
end

function display.divisionColor(node,v)
    if cc.isDead(node) then
        return
    end
    if node.setColor then
        local c = node:getColor()
        c.r = c.r / v
        c.g = c.g / v
        c.b = c.b / v
        node:setColor(c)
    end
    if not node:isCascadeColorEnabled() then
        local children = node:getChildren()
        for i,child in ipairs(children) do
            display.divisionColor(child,v)
        end
    end
end

-- sprite 要添加 shader 的 sprite
-- name 添加shader的名字（Shader开头）
function display.applySpriteShader(sprite, name)
    if cc.isDead(sprite) then return end

    local texture
    if sprite.getTexture then
        texture = sprite:getTexture()
    end

    name = name or "ShaderPositionTextureColor_noMVP"
    local glprogramstate = cc.GLProgramState:getOrCreateWithGLProgramName(name, texture)
    assert(glprogramstate,"glprogramstate nil")
    sprite:setGLProgramState(glprogramstate)
end


function display.applyShaderByName(node, name)
  if not name then
    name = "ShaderPositionTextureColor_noMVP"
  end
  if( node == nil ) then return end
  local children=node:getChildren()
  if(#children>0)then
      for i=1,#children do
        display.applyShaderByName(children[i],name)
      end
  else
      local render = nil
      local is_mvp = false
      if(tolua.type(node)=="ccui.ImageView")then
          render = node:getVirtualRenderer():getSprite()
      elseif(tolua.type(node)=="cc.Sprite")then
          render = node
      elseif(tolua.type(node)=="cc.Scale9Sprite")then
          render = node:getSprite()
      end

      if(render~=nil)then
          local state = cc.GLProgramState:getOrCreateWithGLProgramName(name, render:getTexture())
          if state then
            render:setGLProgramState(state)
          end
      end
  end
end


function display.dumpTree(node,t)
    if cc.isDead(node) then
        return
    end
    local name = node:getName()
    t[name]={}
    local children = node:getChildren()
    for i,child in ipairs(children) do
        display.dumpTree(child,t[name])
    end
end

function display.getNodeCount(node)
    if cc.isDead(node) then
        return 0
    end
    local count = 1
    local children = node:getChildren()
    for _,child in ipairs(children) do
        count = count + display.getNodeCount(child)
    end
    return count
end

function display.dumpNode(node,depth)
    if cc.isDead(node) then
        return
    end

    local out = {}

    local function _dumpNode(n,t,idx)
        local key = n:getName().."_"..n:getTag().."_"..idx
        t[key]={}
        local children = n:getChildren()
        for idx,child in ipairs(children) do
            _dumpNode(child,t[key],idx)
        end
    end

    _dumpNode(node,out,0)
    dump(out,"dumpNode",depth)
end

function display.newLensFlareEffect()
    local sn = nil
    if custom.ShaderNode then
        sn = custom.ShaderNode:shaderNodeWithVertex("", "res/shader/LensFlare.fsh");
        sn:setBlendFunc(gl.SRC_ALPHA,gl.ONE);

        local seqAction =  cc.Sequence:create(
          cc.Show:create(),
          cc.FadeIn:create(0.2),
          cc.DelayTime:create(2),
          cc.FadeOut:create(0.5),
          cc.Hide:create(),
          cc.DelayTime:create(50))
        sn:runAction(cc.RepeatForever:create(seqAction))
    end
    return sn
end
